package com.gxa.user.service.impl;

import com.gxa.o2o.core.dto.ResultDTO;
import com.gxa.o2o.core.exception.BusinessException;
import com.gxa.o2o.core.pojo.User;
import com.gxa.o2o.core.service.impl.BaseServiceImpl;

import com.gxa.o2o.core.utils.SnowFlake;
import com.gxa.user.mapper.UserMapper;
import com.gxa.user.service.UserService;
import com.gxa.user.utils.SmsUtil;
import com.gxa.user.utils.TencentCOS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 阔爱又迷人的川锅锅呀
 */
@Service("userService")
@Transactional(rollbackFor = Exception.class)
@Slf4j

public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {
    @Resource
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SmsUtil smsUtil;
    @Autowired
    private RestTemplate restTemplate;
    public static final String LOGIN="O2O:LOGIN_TOKEN:";
    private static  final String CLIENT_ID="56955724afa8d7bf2e04273b405461d61d90a0eb995b457f60ea2dca7fcf2960";

    private static  final String CLIENT_SECRET="10436df17ac2a706cc9bee852284720eb738deba10132a0d814f4fa0873fd5ba";

    private static final String REDIRECT_URL="http://172.16.14.112:8101/user/authorization_code";
    private static final String VERIFY_CODE="O2O:VerifyCode:";
    @Override
    public ResultDTO upload(MultipartFile file, String folder) throws IOException {
        //获取文件的名称
        String fileName = file.getOriginalFilename();

        //获取文件后缀
        String prefix = fileName.substring(fileName.lastIndexOf("."));

        //使用uuid作为文件名，防止生成的临时文件重复
        File tempFile = File.createTempFile("image-" + UUID.randomUUID().toString().replace("-", ""), prefix);

        //将MultipartFile转换成File
        file.transferTo(tempFile);

        //上传文件到腾讯云存储
        //调用腾讯云工具上传文件
        String imageName = TencentCOS.uploadfile(tempFile, folder);

        //程序结束时，删除临时文件
        deleteFile(tempFile);

        log.debug("upload image url is {}", imageName);
        return new ResultDTO(200, "上传成功", "https://wjt-1306520233.cos.ap-chengdu.myqcloud.com/" + imageName);

    }

    @Override
    public void loginByGit(HttpServletResponse response) throws IOException {
        response.sendRedirect("http://gitee.com/oauth/authorize?client_id=" +
                "56955724afa8d7bf2e04273b405461d61d90a0eb995b457f60ea2dca7fcf2960&"  +
                "redirect_uri=http://172.16.14.112:8101/user/authorization_code&response_type=code");
    }

    /**
     * 第三方登录服务回调接口
     * @param code
     * @param request
     * @return
     * @throws BusinessException
     */
    @Override
    public ResultDTO callBack(String code, HttpServletRequest request) throws BusinessException {
        System.out.println("111111111111111111111111");
        System.out.println(request.getHeader("referer"));
        System.out.println("111111111111111111111111");
        String authorizationUrl ="https://gitee.com/oauth/token";
        Map<String, String> codeMap = new HashMap<>(16);
        codeMap.put("grant_type","authorization_code");
        codeMap.put("code",code);
        codeMap.put("client_id",CLIENT_ID);
        codeMap.put("redirect_uri",REDIRECT_URL);
        codeMap.put("client_secret",CLIENT_SECRET);
        Map userCodeMap = restTemplate.postForObject(authorizationUrl , codeMap, Map.class);
        HttpHeaders httpheaders = new HttpHeaders();
        assert userCodeMap != null;
        httpheaders.add("Authorization", "token " +
                "" + userCodeMap.get("access_token"));
        HttpEntity<?> httpEntity = new HttpEntity<>(httpheaders);
        ResponseEntity<Map> exchange = restTemplate.exchange("https://gitee.com/api/v5/user", HttpMethod.GET, httpEntity, Map.class);
        System.out.println("exchange.getBody() = " + exchange.getBody());
        /*
         *获取用户id
         */
        String userId=exchange.getBody().get("id").toString();
        User gitUser = new User();
        gitUser.setId(userId);
        /*
         * 获取用户名
         */
        String userName = (String) exchange.getBody().get("name");
        gitUser.setName(userName);
        String userHeadImg=(String)exchange.getBody().get("avatar_url");
        gitUser.setUserHeadImage(userHeadImg);
        gitUser.setRegTime(new Date(System.currentTimeMillis()));
        gitUser.setLoginTime(new Date(System.currentTimeMillis()));
        User dbUser = userMapper.selectByPrimaryKey(userId);
        System.out.println("1111111111111");
        System.out.println(dbUser);
        /*
         * 判断当前用户是否存在
         */
        if (dbUser==null) {

            int res = userMapper.insert(gitUser);
            if (res==1){
                String token = UUID.randomUUID().toString().replace("-", "");
                //登陆成功将token存入数据库 以便二次登录删除重复token时作数据获取来源
                gitUser.setToken(token);
                userMapper.updateByPrimaryKeySelective(gitUser);
                redisTemplate.opsForValue().set(LOGIN+token,gitUser,60*60*2, TimeUnit.SECONDS);
                return new ResultDTO(200,"登录成功",token);
            }
            log.error("用户："+userName+"第三方登录异常！");
            throw  new BusinessException("网络异常");
        }
        /*
         * 用户已注册在库 判断状态
         */
        if (dbUser.getStatus()&&dbUser.getDelete()) {
            log.info("异常用户："+dbUser.getName()+new Date(System.currentTimeMillis())+"尝试登录！");
            throw new BusinessException("用户状态异常");
        }
        /*
         * 清除上次登录存入redis中的token
         */
        redisTemplate.delete(LOGIN+dbUser.getToken());
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(LOGIN+token,dbUser,60*60*2, TimeUnit.SECONDS);
        gitUser.setToken(token);
        gitUser.setLoginTime(new Date(System.currentTimeMillis()));
        userMapper.updateByPrimaryKeySelective(gitUser);
        return new ResultDTO(200, "登录成功", token);
    }

    /**
     * 用户手机一键登录
     * @param phone
     * @param code
     * @return
     */
    @Override
    public ResultDTO loginByPhone(String phone, String code) {
        /*先判断参数是否为空*/
        if (phone==null||phone==""||code==null||code=="") {
            return new ResultDTO(1001, "手机号或验证码不能为空");
        }
        /*获取reids中验证码*/
        String redisVerifyCode = (String) redisTemplate.opsForValue().get(VERIFY_CODE + phone + ":code");
        /*判断验证码是否有效*/
        if (redisVerifyCode==null||redisVerifyCode=="") {
            return new ResultDTO(1001,"验证码已失效");
        }
        /*校验验证码*/
        if (!code.equalsIgnoreCase(redisVerifyCode)) {
            return new ResultDTO(1001, "验证码不正确！");
        }
        /*校验通过判断数据库中数据是否存在*/
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria().andEqualTo("phone", phone);
        User user = userMapper.selectOneByExample(example);
        /*用户不存在进行一键注册操作*/
        if (user==null) {
           user.setRegTime(new Date(System.currentTimeMillis()));
           user.setId(SnowFlake.nextId()+"");
           user.setName("用户："+phone);
           userMapper.insert(user);
        }
        /*用户存在直接返回token*/
        /*先清除上次登录的token*/
        redisTemplate.delete(LOGIN+user.getToken());
        /*生成当前登录token*/
        String token=SnowFlake.nextId()+"";
        /*将token存入redis*/
        redisTemplate.opsForValue().set(LOGIN+token,user);
        user.setToken(token);
        userMapper.updateByPrimaryKeySelective(user);
        return new ResultDTO(200,"登录成功",token);
    }

    @Override
    public ResultDTO getVerifyCode(String phone) throws BusinessException {
        /*
         *声明一个map用来装短信发送次数、60内重复发送，以及短信验证码
         */
        HashMap<String, Object> codeMap = new HashMap<>(16);
        /*
         *查看缓存中验证码是否过期
         */
        Map<String,Object> redisMap = (Map<String, Object>) redisTemplate.opsForValue().get(VERIFY_CODE + phone+":codeMap");
        System.out.println(redisMap);
       /*先判断当天请求次数*/
        if (redisMap!=null&&(Integer)redisMap.get("requestTimes")>=10) {
            return new ResultDTO(1001,"当天请求次数过多，请明天再试！");
        }
        /* 获取当前时间戳*/
        long nowTime = new Date(System.currentTimeMillis()).getTime();
        /*判断60秒内重复请求*/
        if (redisMap!=null&& (new Date((long)redisMap.get("nowTime")+60*1000).getTime())>=nowTime) {
            return new ResultDTO(1001,"60s内无法再次请求，请稍后再试！");
        }
        /*
         *获取随机验证码
         */
        String code = smsUtil.getCode();
        /*
         *将验证码发送至用户手机
         */
        Boolean result = smsUtil.sendMessage(phone, code);
        if (!result) {
            throw new  BusinessException("短信验证码发送失败！");
        }
        /*
         *将验证码保存至redis过期时间为5分钟
         */
        Integer requestTimes=1;
        if (redisMap!=null) {
            requestTimes= (Integer) redisMap.get("requestTimes")+1;
        }
        codeMap.put("nowTime",nowTime);
        codeMap.put("requestTimes",requestTimes);
        redisTemplate.opsForValue().set(VERIFY_CODE+phone+":code",code,60*5,TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(VERIFY_CODE+phone+":codeMap",codeMap,12,TimeUnit.HOURS);
        System.out.println(redisMap);
        System.out.println(codeMap);
        return new ResultDTO(200,"短信验证码已成功发送！");
    }

    /**
     * 删除临时文件
     *
     * @param files 临时文件，可变参数
     */
    private void deleteFile(File... files) {
        for (File file : files) {
            if (file.exists()) {
                file.delete();
            }
        }
    }
}